home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / ISSUE17 / CGI / CGIAPI.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-10-29  |  7.7 KB  |  293 lines

  1. unit CGIAPI;
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes, INIFIles;
  7.  
  8. type
  9.   TEnvironmentType = (etStdCGI, etWinCGI);
  10.  
  11.   TCGI = class
  12.   private
  13.     FCGIItems: TStringList;
  14.     FFormItems: TStringList;
  15.     FEnvironmentType: TEnvironmentType;
  16.     FOutputFile: TextFile;
  17.     FWinCGIProfileName: string;
  18.     FWinCGIProfile: TINIFile;
  19.   protected
  20.     constructor Create; virtual;
  21.     destructor Destroy; override;
  22.     procedure LoadStdCGIUserData;
  23.     procedure LoadWinCGIUserData;
  24.     procedure UnpackURLString( S: PChar ); virtual;
  25.   public
  26.     procedure DumpWinCGIProfile;
  27.     function GetEnv(Variable: string): string;
  28.     procedure Write(Value: string);
  29.     procedure WriteLn(Value: string);
  30.     property CGIItems: TStringList read FCGIItems;
  31.     property EnvironmentType: TEnvironmentType read FEnvironmentType;
  32.     property FormItems: TStringList read FFormItems;
  33.     property OutputFile: TextFile read FOutputFile write FOutputFile;
  34.     property WinCGIProfile: TINIFile read FWinCGIProfile;
  35.   end;
  36.  
  37. var
  38.   CGI: TCGI;
  39.  
  40. implementation
  41.  
  42. uses
  43.   SysUtils, Windows;
  44.  
  45. const
  46.   NumCGIVars = 15;
  47.  
  48.   { These are the standard names used by the calling application
  49.     to reference CGI variables.  They generally follow the
  50.     WinCGI names. }
  51.   CGIVarNames: array[0..NumCGIVars - 1] of string[31] =
  52.     ('SERVER SOFTWARE',
  53.      'SERVER NAME',
  54.      'SERVER PORT',
  55.      'CGI VERSION',
  56.      'REQUEST PROTOCOL',
  57.      'REQUEST METHOD',
  58.      'LOGICAL PATH',
  59.      'PHYSICAL PATH',
  60.      'EXECUTABLE PATH',
  61.      'QUERY STRING',
  62.      'REMOTE HOST',
  63.      'REMOTE ADDRESS',
  64.      'REMOTE USER',
  65.      'CONTENT LENGTH',
  66.      'CONTENT TYPE');
  67.  
  68.   { These are the actual variable names used by each protocol. }
  69.   CGIVars: array[0..NumCGIVars - 1, TEnvironmentType] of string[31] =
  70.      { etStdCGI              etWinCGI }
  71.     (
  72.      ('SERVER_SOFTWARE',    'SERVER SOFTWARE'),
  73.      ('SERVER_NAME',        'SERVER NAME'),
  74.      ('SERVER_PORT',        'SERVER PORT'),
  75.      ('GATEWAY_INTERFACE',  'CGI VERSION'),
  76.      ('SERVER_PROTOCOL',    'REQUEST PROTOCOL'),
  77.      ('REQUEST_METHOD',     'REQUEST METHOD'),
  78.      ('PATH_INFO',          'LOGICAL PATH'),
  79.      ('PATH_TRANSLATED',    'PHYSICAL PATH'),
  80.      ('SCRIPT_NAME',        'EXECUTABLE PATH'),
  81.      ('QUERY_STRING',       'QUERY STRING'),
  82.      ('REMOTE_HOST',        'REMOTE HOST'),
  83.      ('REMOTE_ADDR',        'REMOTE ADDRESS'),
  84.      ('REMOTE_USER',        'REMOTE USER'),
  85.      ('CONTENT_LENGTH',     'CONTENT LENGTH'),
  86.      ('CONTENT_TYPE',       'CONTENT TYPE')
  87.      );
  88.  
  89. constructor TCGI.Create;
  90. var
  91.   I: Integer;
  92. begin
  93.   inherited Create;
  94.  
  95.   FCGIItems := TStringList.Create;
  96.   FFormItems := TStringList.Create;
  97.  
  98.   { Detect whether we are standard CGI or WinCGI. }
  99.   if GetEnv('SERVER_NAME') <> '' then
  100.     FEnvironmentType := etStdCGI
  101.   else
  102.   begin
  103.     FEnvironmentType := etWinCGI;
  104.     FWinCGIProfileName := ParamStr(1);
  105.     FWinCGIProfile := TINIFile.Create(FWinCGIProfileName);
  106.   end;
  107.  
  108.   { Assign and open our output file accordingly. }
  109.   case EnvironmentType of
  110.     etStdCGI: AssignFile(OutputFile, '');
  111.     etWinCGI: AssignFile(OutputFile, WinCGIProfile.ReadString('System', 'Output File', ''));
  112.   end;
  113.   Rewrite(OutputFile);
  114.  
  115.   { Write standard HTML header for the output page. }
  116.   WriteLn('Content-type: text/html');
  117.   WriteLn('');
  118.  
  119.   { Load CGI variables and user's form variables. }
  120.   case EnvironmentType of
  121.     etStdCGI: begin
  122.                 for I := 0 to NumCGIVars - 1 do
  123.                   FCGIItems.Values[CGIVarNames[I]] :=
  124.                     GetEnv(CGIVars[I, etStdCGI]);
  125.  
  126.                 LoadStdCGIUserData;
  127.               end;
  128.     etWinCGI: begin
  129.                 for I := 0 to NumCGIVars - 1 do
  130.                   FCGIItems.Values[CGIVarNames[I]] :=
  131.                     WinCGIProfile.ReadString('CGI', CGIVars[I, etWinCGI], '');
  132.  
  133.                 LoadWinCGIUserData;
  134.               end;
  135.   end;
  136. end;
  137.  
  138. destructor TCGI.Destroy;
  139. begin
  140.   CloseFile(OutputFile);
  141.  
  142.   FCGIItems.Free;
  143.   FFormItems.Free;
  144.   FWinCGIProfile.Free;
  145. end;
  146.  
  147. procedure TCGI.DumpWinCGIProfile;
  148. { Writes the contents of the WinCGI profile file to the
  149.   response page. }
  150. var
  151.   FCB: TextFile;
  152.   Rec: string;
  153. begin
  154.   if FWinCGIProfile <> nil then
  155.   begin
  156.     AssignFile(FCB, FWinCGIProfileName);
  157.     Reset(FCB);
  158.     try
  159.       while not Eof(FCB) do
  160.       begin
  161.         ReadLn(FCB, Rec);
  162.         WriteLn(Rec + '<BR>');
  163.       end;
  164.     finally
  165.       CloseFile(FCB);
  166.     end;
  167.   end;
  168. end;
  169.  
  170. function TCGI.GetEnv(Variable: string): string;
  171. { Returns the value iof the given environment variable. }
  172. var
  173.   EnvVariable: array[0..127] of char;
  174.   EnvBuffer: array[0..1023] of char;
  175. begin
  176.   StrPCopy(EnvVariable, Variable);
  177.   Result := '';
  178.   if GetEnvironmentVariable(PChar(Variable), @EnvBuffer, SizeOf(EnvBuffer)) <> 0 then
  179.     Result := StrPas(EnvBuffer);
  180. end;
  181.  
  182. procedure TCGI.LoadStdCGIUserData;
  183. { Reads, parses, and decodes values for the standard CGI form variables. }
  184. var
  185.   ContentLength: LongInt;
  186.   InputFCB: File;
  187.   InputBuffer: PChar;
  188.   RequestMethod: string;
  189.   UserContentBuffer: string;
  190. begin
  191.   RequestMethod := Uppercase(FCGIItems.Values['REQUEST METHOD']);
  192.  
  193.   { If the form action is a POST, then we get form variables from
  194.     the standard input device. }
  195.   if RequestMethod = 'POST' then
  196.   begin
  197.     if FCGIItems.Values['CONTENT TYPE'] <> '' then
  198.     begin
  199.       ContentLength := StrToInt(FCGIItems.Values['CONTENT LENGTH']);
  200.       AssignFile(InputFCB, '');  { standard input }
  201.       Reset(InputFCB, 1);
  202.       try
  203.         InputBuffer := StrAlloc(ContentLength + 1);
  204.         FillChar(InputBuffer^, ContentLength + 1, #0);
  205.         try
  206.           BlockRead(InputFCB, InputBuffer^, ContentLength);
  207.           UnpackURLString(InputBuffer);
  208.         finally
  209.           StrDispose(InputBuffer);
  210.         end;
  211.       finally
  212.         CloseFile(InputFCB);
  213.       end;
  214.     end;
  215.   end
  216.  
  217.   { If the form action is GET, then we get form variables from
  218.     from the QUERY STRING variable. }
  219.   else if RequestMethod = 'GET' then
  220.   begin
  221.     UserContentBuffer := FCGIItems.Values['QUERY STRING'];
  222.     InputBuffer := StrAlloc(Length(UserContentBuffer));
  223.     try
  224.       StrPCopy(InputBuffer, UserContentBuffer);
  225.       UnpackURLString(InputBuffer);
  226.     finally
  227.       StrDispose(InputBuffer);
  228.     end;
  229.   end;
  230. end;
  231.  
  232. procedure TCGI.LoadWinCGIUserData;
  233. { Copies values for WinCGI form variables. }
  234. begin
  235.   { All form variables are found in the [Form Literal] section of
  236.     the profile file. }
  237.   WinCGIProfile.ReadSectionValues('Form Literal', TStrings(FFormItems));
  238. end;
  239.  
  240. procedure TCGI.UnpackURLString( S: PChar );
  241. { Parses and decodes a URL-encoded string.  Copies variable values into
  242.   the FFormItems field. }
  243. var
  244.   LabelStr: ShortString;
  245.   ValueStr: ShortString;
  246. begin
  247.   LabelStr := '';
  248.   ValueStr := '';
  249.   while S^ <> #0 do
  250.   begin
  251.     case S^ of
  252.       '+' : ValueStr := ValueStr + ' ';
  253.       '%' : begin
  254.               ValueStr := ValueStr + Chr(StrToInt('$' + (S + 1)^ + (S + 2)^));
  255.               Inc(S, 2);
  256.             end;
  257.       '=' : if LabelStr = '' then
  258.             begin
  259.               LabelStr := ValueStr;
  260.               ValueStr := '';
  261.             end;
  262.       '&' : begin
  263.               FFormItems.Values[LabelStr] := ValueStr;
  264.               ValueStr := '';
  265.               LabelStr := '';
  266.             end;
  267.       else ValueStr := ValueStr + S^;
  268.     end;
  269.     Inc(S);
  270.   end;
  271.  
  272.   if ValueStr <> '' then
  273.     FFormItems.Values[LabelStr] := ValueStr;
  274. end;
  275.  
  276. procedure TCGI.Write(Value: AnsiString);
  277. { Standard Write to the output page. }
  278. begin
  279.   System.Write(OutputFile, Value);
  280. end;
  281.  
  282. procedure TCGI.WriteLn(Value: AnsiString);
  283. { Standard WriteLn to the output page. }
  284. begin
  285.   System.WriteLn(OutputFile, Value);
  286. end;
  287.  
  288. initialization
  289.   CGI := TCGI.Create;
  290. finalization
  291.   CGI.Free;
  292. end.
  293.